/*
 * Copyright (c) 2011 Norbert Kopcsek
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.modulr.service {

	import org.modulr.bundle.IBundleContext;

	/**
	 * The ServiceInjector listens for a service name and injects the service into the given property.
	 *
	 * @author Norbert Kopcsek
	 */
	public class ServiceInjector extends Injector {


		//------------------------------------------------------------------------------
		//
		//   Constructor 
		//
		//------------------------------------------------------------------------------

		public function ServiceInjector( context:IBundleContext = null, serviceName:String = null, target:Object = null, property:String = null, serviceFilter:Object = null ) {
			super( context, serviceName, serviceFilter );
			this.target = target;
			this.property = property;
		}


		//------------------------------------------------------------------------------
		//
		//   Properties (Getter/Setter) 
		//
		//------------------------------------------------------------------------------

		//--------------------------------------
		// target 
		//--------------------------------------

		/**
		 * The target object which will hold the service in the given property.
		 */
		public function get target():Object {
			return _target;
		}

		public function set target( value:Object ):void {
			if ( value == _target ) {
				return;
			}
			_target = value;

			updateTargetProperty();
		}

		//--------------------------------------
		// property 
		//--------------------------------------

		/**
		 * The name of the property to be set on the target object.
		 */
		public function get property():String {
			return _property;
		}

		public function set property( value:String ):void {
			if ( value == _property ) {
				return;
			}
			_property = value;

			updateTargetProperty();
		}

		//--------------------------------------
		// service 
		//--------------------------------------

		/**
		 * The service to be set on the target object.
		 */
		public function get service():Object {
			return _service;
		}

		public function set service( value:Object ):void {
			if ( value == _service ) {
				return;
			}
			_service = value;

			updateTargetProperty();
		}


		//------------------------------------------------------------------------------
		//
		//   Protected fields 
		//
		//------------------------------------------------------------------------------

		/**
		 * @private
		 */
		protected var _target:Object;

		/**
		 * @private
		 */
		protected var _property:String;

		/**
		 * @private
		 */
		protected var _currentServiceReference:IServiceReference;

		/**
		 * @private
		 */
		protected var _service:Object;


		//------------------------------------------------------------------------------
		//
		//   Overridden methods 
		//
		//------------------------------------------------------------------------------

		/**
		 * @private
		 * Adds a service reference.
		 */
		override protected function installServiceReference( serviceReference:IServiceReference ):void {
			if ( currentServiceReference == null ) {
				currentServiceReference = serviceReference;
			}
		}

		/**
		 * @private
		 * Removes a service reference.
		 */
		override protected function uninstallServiceReference( serviceReference:IServiceReference ):void {
			if ( currentServiceReference == serviceReference ) {
				currentServiceReference = serviceTracker.length > 0 ? serviceTracker.getItemAt( 0 ) as IServiceReference : null;
			}
		}


		//------------------------------------------------------------------------------
		//
		//   Protected methods 
		//
		//------------------------------------------------------------------------------

		/**
		 * @private
		 */
		protected function get currentServiceReference():IServiceReference {
			return _currentServiceReference;
		}

		/**
		 * @private
		 */
		protected function set currentServiceReference( value:IServiceReference ):void {
			if ( value == _currentServiceReference ) {
				return;
			}
			var oldValue:IServiceReference = _currentServiceReference;
			_currentServiceReference = value;

			var ungetSuccessful:Boolean = true;

			if ( oldValue != null ) {
				ungetSuccessful = oldValue.registration.ungetService( context );
				service = null;
			}

			if ( value != null ) {
				service = value.registration.getService( context );
			}
		}

		/**
		 * @private
		 * Updates the target property with service if possible.
		 */
		protected function updateTargetProperty():void {
			if ( target == null || property == null || !target.hasOwnProperty( property )) {
				return;
			}

			target[ property ] = service;
		}
	}
}

